#ifndef _XML_PARSE_H_
#define _XML_PARSE_H_

#include <Windows.h>

#include <string>
#include <map>
#include <queue>
#include <list>

using namespace std;

enum NODE_TYPE {
	VERSION_NODE,
	COMMENT_NODE,
	CLOSED_NODE,
	BEGIN_NODE,
	END_NODE
};

class file_base {
protected:
	HANDLE h_file;
	char buffer[1024];
	DWORD cur_pos, num_read;
public:
	file_base(const string& file_name);
	~file_base() {
		if (h_file != NULL && h_file != INVALID_HANDLE_VALUE)
			CloseHandle(h_file);
	}
};

class file_line:private file_base {
public:
	file_line(const string& file_name):file_base(file_name) {};
	// return the length of the line
	int get_line(string& line);
};

class file_node:private file_base {
	static const char NODE_BEGIN = '<';
	static const char NODE_END = '>';
public:
	file_node(const string& file_name):file_base(file_name) {};
	// return the length of the node
	int get_node(string& node);
};

typedef class map<string, string> VAL_MAP;
typedef VAL_MAP::iterator VI;

class xml_node {
	NODE_TYPE type;
	string name;
	VAL_MAP values; // the key-val map in a ascending order
	queue<string> key_order; // record the real order of the values
	class xml_node *parent;
	class xml_node *first_child;
	class xml_node *last_child;
	class xml_node *next_sibling;
public:
	// 
	xml_node();
	xml_node(class xml_node& copy);
	xml_node(class xml_node *p);

	// infact we can maintain the level infomation while we are traversing the tree
	int get_level();
	
	NODE_TYPE get_type() { return type;}
	string get_name() { return name;}
	class xml_node *get_parent() { return parent;}
	class xml_node *get_first_child() { return first_child; }
	class xml_node *get_sibling() { return next_sibling; }

	void set_type(NODE_TYPE t) { type = t;}
	void set_name(const string& n) { name = n;}
	void set_parent(class xml_node *p);
	void add_child(class xml_node *c);
	void add_sibling(class xml_node *s);
	
	void remove_child(class xml_node *c);

	void remove_all_children();
	void remove_all_siblings();

	// set the content of this node, return the type of the node.
	NODE_TYPE set_content(const string& content);

	void get_val(const string& key, string& val);
	// set the value of the specified key in the map, and update the content string
	void set_val(const string& key, const string& val);
	
	bool is_equal_to(class xml_node *n);

	void to_string(string& content);
	void tree_to_string(string& content);
};

typedef list<class xml_node *> NL;
typedef list<class xml_node *>::const_iterator NLI;

class xml_parser {
private:
	class xml_node *root;
public:
	xml_parser(const string& in_file_name);
	~xml_parser();
	class xml_node *get_root_node() { return root; };
	void find_node_byname(xml_node *node, const string& name, NL& node_list);
	int write_xml(const string& out_file_name);
};

#endif